package com.streambolics.appengine;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.streambolics.data.Person;
import com.streambolics.std.AnchorBuilder;

/**
 * A servlet that knows about the user.
 * <p>
 * The user is identified by the Google User Service, and translates to a Person
 * object.
 * </p>
 * 
 * @author Sauron
 * 
 * @param <T>
 */

public abstract class UserAwareServlet<T> extends PersistenceAwareServlet<T>
{
    private static final long serialVersionUID = 1L;

    private Person            _Person;
    private UserService       _UserService;
    private boolean           _NoRightsReported;

    @Override
    protected void addTopMenuItems (AnchorBuilder aBuilder, T aResponseObject) throws Exception
    {
        if (getPerson () != null)
        {
            aBuilder.addAnchor ("/go/User", _Person.getEmail ());
            aBuilder.addAnchor (getLogoutURL (), "Log-out");
        }
        else
        {
            aBuilder.addAnchor (getLoginURL (), "Log-in");
        }
        super.addTopMenuItems (aBuilder, aResponseObject);
    }

    @Override
    protected T generateResponseObject (HttpServletRequest aRequest) throws Exception
    {
        // TODO Auto-generated method stub
        return null;
    }

    protected long getCurrentUserId ()
    {
        try
        {
            Person p = getPerson ();
            if (p == null)
            {
                return -1;
            }
            else
            {
                return p.getId ();
            }
        }
        catch (Exception e)
        {
            return -1;
        }
    }

    protected String getLoginURL ()
    {
        return getUserService ().createLoginURL (getReturnUrl ());
    }

    protected String getLogoutURL ()
    {
        return getUserService ().createLogoutURL ("/index.html");
    }

    /**
     * The Person record from the database corresponding to the current user.
     * <p>
     * The person can be retrieved by numerous automated ways:
     * </p>
     * <ul>
     * <li>
     * The Session object maintained by the servlet container.</li>
     * <li>
     * The e-mail of the user logged by Google User Service.</li>
     * <li>
     * The USERKEY parameter from the request</li>
     * <li>
     * The person attached to the object currently displayed (for example, if
     * the servlet is meant to display a message retrieved by a MessageId, the
     * returned Person object would be the recipient of the message.)</li>
     * </ul>
     */

    protected Person getPerson () throws Exception
    {
        if (_Person == null)
        {
            User googleUser = getUserService ().getCurrentUser ();
            if (googleUser != null && googleUser.getEmail () != null)
            {
                _Person = Person.accessByEmail (getDatabase (), googleUser.getEmail ());

                // TODO : Check that the UserKey is valid, throw UserMismatch
                // otherwise

                clearSession ("UserId");
            }
        }

        if (_Person == null)
        {
            String uk = getParameter ("UserKey");
            if (uk != null)
            {
                _Person = Person.locateByUserKey (getDatabase (), uk);
            }

            if (_Person != null)
            {
                setSession ("UserId", _Person.getId ());
            }
        }

        if (_Person == null)
        {
            Integer sid = (Integer) getSession ("UserId");
            if (sid != null)
            {
                _Person = Person.load (getDatabase (), sid);
            }
        }

        if (_Person == null)
        {
            // TODO : Create a special UnidentifiedPerson
        }

        return _Person;
    }

    /**
     * The Google User Service
     */

    protected UserService getUserService ()
    {
        if (_UserService == null)
        {
            _UserService = UserServiceFactory.getUserService ();
        }
        return _UserService;
    }

    /**
     * Whether the currently logged user has the right to modify the given model
     * object.
     * 
     * @param aResponseObject
     * @return
     */

    protected boolean hasWritePermission (T aResponseObject)
    {
        return true;
    }

    protected boolean isUser (long aUserId)
    {
        return getCurrentUserId () == aUserId;
    }

    protected void mustBeUserId (long id) throws Exception
    {
        if (getCurrentUserId () != id)
        {
            throw new MissingUserException (getRequest ());
        }
    }

    protected void reportNoWritePermission ()
    {
        if (!_NoRightsReported)
        {
            warnAbout (new Exception ("You do not have the rigths to change this. The changes have not been applied."));
        }
    }

    /**
     * The identified user.
     * 
     * This is similar to getPerson, but requires the user to be properly
     * identified.
     * 
     * @return
     * @throws Exception
     */

    protected Person requireIdentifiedPerson () throws Exception
    {
        // TODO : When getPerson will return an unidentified, throw exception.
        // TODO : The exception should be thrown by the object itself.

        if (getPerson () == null)
        {
            throw new MissingUserException (getRequest ());
        }
        return _Person;
    }

    protected boolean requireWritePermission (T aResponseObject)
    {
        if (!hasWritePermission (aResponseObject))
        {
            reportNoWritePermission ();
            return false;
        }
        else
        {
            return true;
        }
    }

    @Override
    protected void setupEnvironment (HttpServletRequest aRequest, HttpServletResponse aResponse) throws Exception
    {
        super.setupEnvironment (aRequest, aResponse);
        _Person = null;
        _NoRightsReported = false;
    }
}
